package bean;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.management.RuntimeErrorException;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

public class MyBeanFactory {

	private List<MyBeanDefinition> beanDefinitions;
	
	private Map<String,Object> singletionBeans;
	private Map<String,MyBeanDefinition> prototypeBeans;
	
	public MyBeanFactory(){
		beanDefinitions = new ArrayList<MyBeanDefinition>();
		singletionBeans = new HashMap<String, Object>();
		prototypeBeans = new HashMap<String, MyBeanDefinition>();
		
		parse();
		resolveBeanDefinitions();
	}
	public Object getBean(String beanName){
		if(singletionBeans.containsKey(beanName)){
			return singletionBeans.get(beanName);
		}
		MyBeanDefinition definition = prototypeBeans.get(beanName);
		if(definition !=null){
			String className = definition.getClassName();
			try {
				return Class.forName(className).newInstance();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		throw new RuntimeException("Invalid bean name"+beanName);
	}
	public <T> T getBean(String beanName,Class<T> clazz){
		Object bean = getBean(beanName);
		if(bean.getClass().equals(clazz)){
			return (T)bean;
		}
		throw new RuntimeException("the class is not  match the bean class"+clazz+"but actually get"+bean.getClass());
	}
	private void parse(){
		SAXBuilder builder = new SAXBuilder();
		try {
			Document document = builder.build(new File("mybean.xml"));
			Element root = document.getRootElement();
			
			List<Element> beanElements = root.getChildren("bean");
			for(Element beanElement:beanElements){
				String id = beanElement.getAttributeValue("id");
				String clazz = beanElement.getAttributeValue("class");
				String singleton = beanElement.getAttributeValue("singleton");
				
				MyBeanDefinition definition = new MyBeanDefinition();
				definition.setName(id);
				definition.setClassName(clazz);

			if(singleton !=null){
				boolean isSingleton = Boolean.parseBoolean(singleton);
				definition.setSingleton(isSingleton);
			}
			beanDefinitions.add(definition);
			}
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private void resolveBeanDefinitions(){
		for(MyBeanDefinition definition:beanDefinitions){
			String id = definition.getName();
			
			if(definition.isSingleton()){
				String className = definition.getClassName();
				
				Class<?> clazz;
				try {
					clazz = Class.forName(className);
					Object instance = clazz.newInstance();
					this.singletionBeans.put(id, instance);
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				
			}else{
				prototypeBeans.put(id, definition);
			}
		}
	}
}
